/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package spu96a01.impl;

import bP.BP;

import java.util.ArrayList;
import java.util.Collection;

import node1.impl.Node1Impl;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;

import org.eclipse.emf.common.util.EList;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.impl.ENotificationImpl;

import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;

import result.Results;
import spu96a01.Spu96a01;
import spu96a01.Spu96a01Package;
import spu96a01.Task;
import utils.UtilsMaths;
import utils.UtilsModelInstance;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Spu96a01</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link spu96a01.impl.Spu96a01Impl#getBusyPeriod <em>Busy Period</em>}</li>
 *   <li>{@link spu96a01.impl.Spu96a01Impl#getTasks <em>Tasks</em>}</li>
 *   <li>{@link spu96a01.impl.Spu96a01Impl#getWorkload <em>Workload</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class Spu96a01Impl extends Node1Impl implements Spu96a01 {
	/**
	 * The cached value of the '{@link #getBusyPeriod() <em>Busy Period</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getBusyPeriod()
	 * @generated
	 * @ordered
	 */
	protected BP busyPeriod;

	/**
	 * The cached value of the '{@link #getTasks() <em>Tasks</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getTasks()
	 * @generated
	 * @ordered
	 */
	protected EList<Task> tasks;

	/**
	 * The default value of the '{@link #getWorkload() <em>Workload</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWorkload()
	 * @generated
	 * @ordered
	 */
	protected static final int WORKLOAD_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getWorkload() <em>Workload</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWorkload()
	 * @generated
	 * @ordered
	 */
	protected int workload = WORKLOAD_EDEFAULT;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected Spu96a01Impl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return Spu96a01Package.Literals.SPU96A01;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public BP getBusyPeriod() {
		if (busyPeriod != null && busyPeriod.eIsProxy()) {
			InternalEObject oldBusyPeriod = (InternalEObject)busyPeriod;
			busyPeriod = (BP)eResolveProxy(oldBusyPeriod);
			if (busyPeriod != oldBusyPeriod) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, Spu96a01Package.SPU96A01__BUSY_PERIOD, oldBusyPeriod, busyPeriod));
			}
		}
		return busyPeriod;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public BP basicGetBusyPeriod() {
		return busyPeriod;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setBusyPeriod(BP newBusyPeriod) {
		BP oldBusyPeriod = busyPeriod;
		busyPeriod = newBusyPeriod;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, Spu96a01Package.SPU96A01__BUSY_PERIOD, oldBusyPeriod, busyPeriod));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Task> getTasks() {
		if (tasks == null) {
			tasks = new EObjectContainmentEList<Task>(Task.class, this, Spu96a01Package.SPU96A01__TASKS);
		}
		return tasks;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getWorkload() {
		return workload;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setWorkload(int newWorkload) {
		int oldWorkload = workload;
		workload = newWorkload;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, Spu96a01Package.SPU96A01__WORKLOAD, oldWorkload, workload));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case Spu96a01Package.SPU96A01__TASKS:
				return ((InternalEList<?>)getTasks()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case Spu96a01Package.SPU96A01__BUSY_PERIOD:
				if (resolve) return getBusyPeriod();
				return basicGetBusyPeriod();
			case Spu96a01Package.SPU96A01__TASKS:
				return getTasks();
			case Spu96a01Package.SPU96A01__WORKLOAD:
				return new Integer(getWorkload());
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case Spu96a01Package.SPU96A01__BUSY_PERIOD:
				setBusyPeriod((BP)newValue);
				return;
			case Spu96a01Package.SPU96A01__TASKS:
				getTasks().clear();
				getTasks().addAll((Collection<? extends Task>)newValue);
				return;
			case Spu96a01Package.SPU96A01__WORKLOAD:
				setWorkload(((Integer)newValue).intValue());
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case Spu96a01Package.SPU96A01__BUSY_PERIOD:
				setBusyPeriod((BP)null);
				return;
			case Spu96a01Package.SPU96A01__TASKS:
				getTasks().clear();
				return;
			case Spu96a01Package.SPU96A01__WORKLOAD:
				setWorkload(WORKLOAD_EDEFAULT);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case Spu96a01Package.SPU96A01__BUSY_PERIOD:
				return busyPeriod != null;
			case Spu96a01Package.SPU96A01__TASKS:
				return tasks != null && !tasks.isEmpty();
			case Spu96a01Package.SPU96A01__WORKLOAD:
				return workload != WORKLOAD_EDEFAULT;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy()) return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (workload: ");
		result.append(workload);
		result.append(')');
		return result.toString();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public void compute() {

		/**/
		if ((this.busyPeriod != null) && (!done))
		{
			boolean isOverflow = false;
			/**/
			for (Task t : this.tasks) 
			{
				/**/
				if (t.getDeadline() < this.busyPeriod.getValue()) 
				{
					this.workload += (1 + UtilsMaths.floor((this.getBusyPeriod().getValue() - t.getDeadline()), t.getPeriod())) * t.getWcet();
				}
			}
			
//			System.out.println("> (EDF)Workload: " + this.workload);
			
			/**================================ Instance of solution model==============================================*/
			if (this.busyPeriod.getValue() >= this.workload) 
			{
				UtilsModelInstance.createSchedulingResult(this, Results.SCHEDULABLE);
			}
			else 
			{
				UtilsModelInstance.createSchedulingResult(this, Results.NON_SCHEDULABLE);
				isOverflow = true;
			}
			
			/**================================ Search Overflow's maker ==============================================*/
			if (isOverflow) 
			{
				for (Task t_1 : this.tasks) 
				{
					/* Variables */
					ArrayList<Integer> l_deadline = new ArrayList<Integer> ();
					int d = t_1.getDeadline();
					
					/**/
					while (d <= this.getBusyPeriod().getValue())
					{
						/**/
						l_deadline.add(d);
						d += t_1.getDeadline();
					}
					
					/**/
					for (Integer rd : l_deadline) 
					{
						int cumulative = 0;
						/**/
						for (Task t_2 : this.tasks) 
						{
							/**/
							if (t_2.getDeadline() <= rd) 
							{
								cumulative += (1 + UtilsMaths.floor((rd - t_2.getDeadline()), t_2.getPeriod())) * t_2.getWcet();
							}
						}
//						System.out.println ("> Current Task : " + t_1.getId() + " ; rd = " + rd + " ; w = " + cumulative);
						/**/
						if (cumulative > rd)
						{
							isOverflow = false;
							break;
						}
					}
					
				}
			}
			
			done = true;
		}
	}
} //Spu96a01Impl
